package com.yejiarong.auth.bean.dto;

import com.yejiarong.common.validate.annotation.ValueOption;
import jakarta.validation.constraints.*;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author YeJR
 */
@Data
public class OAuth2ClientSaveDto {

    /**
     * client_id
     */
    @Length(max = 100, message = "clientId必须小于等于100")
    @NotBlank(message = "clientId不能为空")
    private String clientId;

    /**
     * client_name
     */
    @Length(max = 200, message = "clientName必须小于等于200")
    @NotBlank(message = "clientName不能为空")
    private String clientName;

    /**
     * client_authentication_methods
     * client_secret_basic：使用 HTTP Basic 认证传输客户端 ID 和密钥。客户端 ID 作为用户名，客户端密钥作为密码。通过 Authorization: Basic <base64编码的client_id:client_secret> 头传输
     *                      使用场景：授权码流程 (Authorization Code)、刷新令牌流程 (Refresh Token)、客户端凭证流程 (Client Credentials)
     * client_secret_post：通过 POST 请求体传输客户端 ID 和密钥。参数为 client_id 和 client_secret
     *                      使用场景：与 client_secret_basic 类似，但某些旧系统可能只支持这种形式
     * client_secret_jwt：使用 JWT 作为客户端断言进行认证。JWT 使用客户端密钥签名。需要预先在授权服务器注册 JWT 配置
     *                      使用场景：需要更安全认证方式的系统。符合 RFC 7523 规范的实现
     * private_key_jwt：使用 JWT 作为客户端断言进行认证。JWT 使用客户端私钥签名（非对称加密）。授权服务器使用注册的公钥验证签名
     *                      使用场景：高安全性要求的系统。客户端有能力安全存储私钥的环境。符合 RFC 7523 规范
     * none：客户端不提供任何认证凭据。仅适用于公共客户端（如SPA应用）
     *                      使用场景：PKCE 流程中的公共客户端。移动应用或浏览器应用
     */
    @ValueOption(multiple = true, values = {"client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"}, message = "clientAuthenticationMethods参考范围：\"client_secret_basic\", \"client_secret_post\", \"client_secret_jwt\", \"private_key_jwt\", \"none\"")
    @NotBlank(message = "clientAuthenticationMethods不能为空")
    private String clientAuthenticationMethods;

    /**
     * authorization_grant_types
     */
    @ValueOption(multiple = true, values = {"authorization_code", "refresh_token", "client_credentials"}, message = "authorizationGrantTypes参考范围：\"authorization_code\", \"refresh_token\", \"client_credentials\"")
    @NotBlank(message = "authorizationGrantTypes不能为空")
    private String authorizationGrantTypes;

    /**
     * redirectUri
     */
    @Length(max = 200, message = "redirectUri必须小于等于1000")
    @NotBlank(message = "redirectUri不能为空")
    private String redirectUri;

    /**
     * post_logout_redirect_uris
     */
    @Length(max = 200, message = "logoutRedirectUri必须小于等于1000")
    @NotBlank(message = "logoutRedirectUri不能为空")
    private String logoutRedirectUri;

    /**
     * scope
     */
    @Size(max = 10, message = "最多10个scope")
    @NotEmpty(message = "scopes不能为空")
    private List<String> scopes;

    /**
     * 授权时是否需要授权
     */
    private boolean requireAuthorizationConsent;

    /**
     * token有效时间
     */
    @NotNull(message = "accessToken有效时间不能为空")
    @Min(value = 1, message = "accessToken有效时间必须大于等于1")
    private Long accessTokenLiveTime = 2L;

    /**
     * token有效时间单位
     */
    @NotBlank(message = "accessToken有效时间单位不能为空")
    @ValueOption(values = {"MINUTES", "HOURS", "DAYS"}, message = "accessToken有效时间单位参考范围：\"MINUTES\", \"HOURS\", \"DAYS\"")
    private String accessTokenLiveTimeUnit = TimeUnit.HOURS.name();

    /**
     * token有效时间
     */
    @NotNull(message = "refreshAccessToken有效时间不能为空")
    @Min(value = 1, message = "refreshAccessToken有效时间必须大于等于1")
    private Long refreshAccessTokenLiveTime = 7L;

    /**
     * token有效时间单位
     */
    @NotBlank(message = "refreshAccessToken有效时间单位不能为空")
    @ValueOption(values = {"MINUTES", "HOURS", "DAYS"}, message = "refreshAccessToken有效时间单位参考范围：\"MINUTES\", \"HOURS\", \"DAYS\"")
    private String refreshAccessTokenLiveTimeUnit = TimeUnit.DAYS.name();
}
